﻿using System;
using System.Collections.Generic;

using System.IO;
using System.Xml;



namespace DailyFx.Book.Repo
{
	using DailyFx.Common;


	public partial class BookImpl 
	{

		/// <summary>
		///		Contains all metrics of tables hosted by the <see cref="DailyFx.Book.IBook"/>
		/// </summary>
		private List<Metrics> _metrics;

		/// <summary>
		///		Contains all symbol definitions for the <see cref="DailyFx.Book.IBook"/> .
		/// </summary>
		private List<Symbol> _symbols;

		/// <summary>
		///		Contains all defined schemas for data <see cref="DailyFx.Book.ITable"/> .
		/// </summary>
		private List<Schema> _schemas;



		/// <summary>
		///		Loads the dbinfo .
		/// </summary>
		private bool parseBookInfo ( )
		{
			string xs	= Path.Combine(this._root, "symbol.xml" );
			string xm	= Path.Combine(this._root, "metrics.xml");
			string xsc	= Path.Combine(this._root, "schema.xml" );

			if ( !File.Exists(xs) || !File.Exists(xm) || !File.Exists(xsc) )
			{
				return false;
			}

			if ( !parseSymbol( xs) )
				return false;
			if ( !parseSchema( xsc) )
				return false;

			if ( !parseMetrics( xm) )
				return false;


			// everything is ok .
			return true;
		}

		/// <summary>
		///		symbol.xml
		/// </summary>
		private bool parseSymbol ( string xpath )
		{

			XmlDocument xdoc = new XmlDocument();
			xdoc.Load( xpath);

			XmlNode xroot = xdoc.SelectSingleNode("DailyFx");
			foreach (var xn in xroot.ChildNodes)
			{
				XmlElement xe = xn as XmlElement;

				if (xe.Name != "Symbol")
					continue;

				Symbol symbol	= new Symbol();
				symbol.Market	= xe.GetAttribute( "market");
				symbol.Category = xe.GetAttribute( "category");
				symbol.Code		= xe.GetAttribute( "code");
				symbol.Ticker	= xe.GetAttribute( "ticker");
				symbol.Text		= xe.GetAttribute( "text");

				this._symbols.Add(symbol);
			}

			// xdoc.Close();
			return true;
		}

		/// <summary>
		///		schema.xml
		/// </summary>
		private bool parseSchema (string xpath )
		{
			XmlDocument xdoc = new XmlDocument();
			xdoc.Load( xpath);

			XmlNode xroot = xdoc.SelectSingleNode( "DailyFx");
			foreach ( var xn in xroot.ChildNodes )
			{
				XmlElement xe = xn as XmlElement;

				if ( xe.Name != "Schema" )
					continue;

				Schema schema = new Schema();
				schema.Alias = xe.GetAttribute( "alias" );

				foreach ( var xn2 in xe.ChildNodes )
				{
					XmlElement xe2 = xn2 as XmlElement;
					if ( xe2.Name != "Field" )
						continue;

					string label	= xe2.GetAttribute( "label" );
					string radix	= xe2.GetAttribute( "radix" );
					string type		= xe2.GetAttribute( "type" );

					schema.AddField( label /*, Convert.ToInt32(radix)*/, 
									Type.GetType("System."+type, false, true) );
				}

				this._schemas.Add ( schema);
			}

			return true;
		}



		/// <summary>
		///		metrices.xml
		/// </summary>
		private bool parseMetrics ( string xpath )
		{

			XmlDocument xdoc = new XmlDocument();
			xdoc.Load( xpath);

			XmlNode xroot = xdoc.SelectSingleNode( "DailyFx");
			foreach ( var xn in xroot.ChildNodes )
			{
				XmlElement xe = xn as XmlElement;

				if (xe.Name != "Table")
					continue;

				Metrics metrics = new Metrics();
				metrics.Table = xe.GetAttribute( "label");

				string[] ss = metrics.Table.Split('.');
				Check.MustValid ( ss.Length == 3, "Not valid table name!");
				
				// symbol .
				Symbol symbol = this.getSymbol( ss[0]);
				metrics.Symbol = symbol;

				// schema .
				Schema schema = this.getSchema( ss[2] );
				metrics.Schema = schema;

				// period .
				Period period = Period.Daily;
				if ( Enum.TryParse( ss[1], out period) )
					metrics.Period = period;
				else 
					metrics.Period = (Period)Convert.ToInt32(ss[1]); // todo:

				
				metrics.Head = DateTime.ParseExact(xe.GetAttribute( "head"), "yyyy.MM.dd", null);
				metrics.Tail = DateTime.ParseExact(xe.GetAttribute( "tail"), "yyyy.MM.dd", null);

				metrics.FieldCount = Convert.ToInt32(xe.GetAttribute( "cols"));
				metrics.RecordCount = Convert.ToInt32(xe.GetAttribute("rows"));

				this._metrics.Add(metrics);

			}

			return true;
		}



		public IReadOnlyList<Metrics> Metrics
		{
			get 
			{ 
				return this._metrics; 
			}
			set
			{
				throw new InvalidOperationException( "");
			}
		}

		public IReadOnlyList<Symbol> Symbols
		{
			get
			{
				return this._symbols;
			}
			set
			{
				throw new InvalidOperationException("");
			}
		}

		public IReadOnlyList<Schema> Schemas
		{
			get
			{
				return this._schemas;
			}
			set
			{
				throw new InvalidOperationException("");
			}
		}

	}
}
